/*
 * @Author: OBKoro1
 * @Date: 2025-09-11 09:21:15
 * @LastEditTime: 2025-09-16 15:05:14
 * @FilePath: \RoPet_ESPS3_AI_EYE-main\main\iot\thing.cc
 * @Description:
 *
 * Copyright (c) 2025 by ${git_name_email}, All Rights Reserved.
 *实现Thing类的JSON序列化和命令调用
 */
#include "thing.h"       // 包含设备基类定义头文件
#include "application.h" // 包含应用层定义头文件

#include <esp_log.h> // 包含ESP-IDF日志库

#define TAG "Thing" // 定义日志标签

namespace iot
{

// 条件编译：仅在启用XIAOZHI协议时定义设备创建器映射表
#if CONFIG_IOT_PROTOCOL_XIAOZHI
    static std::map<std::string, std::function<Thing *()>> *thing_creators = nullptr;
#endif

    /**
     * @brief 注册设备类型创建函数
     * @param type 设备类型名称
     * @param creator 创建该类型设备实例的函数
     *
     * 该函数用于将设备类型与其创建函数关联，存储在全局映射表中
     */
    void RegisterThing(const std::string &type, std::function<Thing *()> creator)
    {
#if CONFIG_IOT_PROTOCOL_XIAOZHI
        // 如果映射表未初始化，则创建新的映射表
        if (thing_creators == nullptr)
        {
            thing_creators = new std::map<std::string, std::function<Thing *()>>();
        }
        // 将设备类型和创建函数存入映射表
        (*thing_creators)[type] = creator;
#endif
    }

    /**
     * @brief 根据设备类型创建设备实例
     * @param type 设备类型名称
     * @return 创建的设备实例指针，如果类型不存在则返回nullptr
     *
     * 通过查找已注册的设备类型映射表，调用对应的创建函数实例化设备
     */
    Thing *CreateThing(const std::string &type)
    {
#if CONFIG_IOT_PROTOCOL_XIAOZHI
        // 在映射表中查找指定类型的创建函数
        auto creator = thing_creators->find(type);
        // 如果未找到对应类型，记录错误日志并返回空指针
        if (creator == thing_creators->end())
        {
            ESP_LOGE(TAG, "Thing type not found: %s", type.c_str());
            return nullptr;
        }
        // 调用创建函数并返回设备实例
        return creator->second();
#else
        return nullptr;
#endif
    }

    /**
     * @brief 生成设备描述信息的JSON字符串
     * @return 包含设备名称、描述、属性和方法的JSON格式字符串
     *
     * 该函数将设备的元数据序列化为JSON格式，用于向外部系统描述设备能力
     */
    std::string Thing::GetDescriptorJson()
    {
        std::string json_str = "{";                                            // 开始构建JSON对象
        json_str += "\"name\":\"" + name_ + "\",";                             // 添加设备名称
        json_str += "\"description\":\"" + description_ + "\",";               // 添加设备描述
        json_str += "\"properties\":" + properties_.GetDescriptorJson() + ","; // 添加属性描述
        json_str += "\"methods\":" + methods_.GetDescriptorJson();             // 添加方法描述
        json_str += "}";                                                       // 结束JSON对象
        return json_str;
    }

    /**
     * @brief 生成设备当前状态的JSON字符串
     * @return 包含设备名称和当前状态的JSON格式字符串
     *
     * 该函数将设备当前状态序列化为JSON格式，用于向外部系统报告设备状态
     */
    std::string Thing::GetStateJson()
    {
        std::string json_str = "{";                            // 开始构建JSON对象
        json_str += "\"name\":\"" + name_ + "\",";             // 添加设备名称
        json_str += "\"state\":" + properties_.GetStateJson(); // 添加设备状态
        json_str += "}";                                       // 结束JSON对象
        return json_str;
    }

    /**
     * @brief 执行设备命令
     * @param command 包含方法名和参数的JSON命令对象
     *
     * 该函数解析传入的命令JSON，查找对应方法并验证参数后执行
     */
    void Thing::Invoke(const cJSON *command)
    {
        // 从命令JSON中提取方法名和参数
        auto method_name = cJSON_GetObjectItem(command, "method");
        auto input_params = cJSON_GetObjectItem(command, "parameters");

        try
        {
            // 查找指定的方法
            auto &method = methods_[method_name->valuestring];

            // 遍历方法的参数列表并验证/设置参数值
            for (auto &param : method.parameters())
            {
                // 从输入参数中获取对应参数值
                auto input_param = cJSON_GetObjectItem(input_params, param.name().c_str());

                // 检查必需参数是否存在
                if (param.required() && input_param == nullptr)
                {
                    throw std::runtime_error("Parameter " + param.name() + " is required");
                }

                // 根据参数类型设置参数值
                if (param.type() == kValueTypeNumber)
                {
                    // 处理数值型参数
                    if (cJSON_IsNumber(input_param))
                    {
                        param.set_number(input_param->valueint);
                    }
                }
                else if (param.type() == kValueTypeString)
                {
                    // 处理字符串型参数
                    if (cJSON_IsString(input_param) || cJSON_IsObject(input_param) || cJSON_IsArray(input_param))
                    {
                        std::string value_str = input_param->valuestring;
                        param.set_string(value_str);
                    }
                }
                else if (param.type() == kValueTypeBoolean)
                {
                    // 处理布尔型参数
                    if (cJSON_IsBool(input_param))
                    {
                        param.set_boolean(input_param->valueint == 1);
                    }
                }
            }

            // 在应用层调度器中执行方法调用，确保线程安全
            Application::GetInstance().Schedule([&method]()
                                                {
                                                    method.Invoke(); // 调用方法
                                                });
        }
        catch (const std::runtime_error &e)
        {
            // 捕获方法未找到异常并记录错误日志
            ESP_LOGE(TAG, "Method not found: %s", method_name->valuestring);
            return;
        }
    }
}